{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "title:migration,new",
    "tags": []
   },
   "source": [
    "# Migrating Custom XGBoost Model with Pre-built Training Container"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "title:migration,new",
    "tags": []
   },
   "source": [
    "### Learning Objectives\n",
    "\n",
    "1. Train a model.\n",
    "2. Upload a model.\n",
    "3. Make a batch and online predictions.\n",
    "4. Deploy a model."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "dataset:iris,lcn"
   },
   "source": [
    "## Introduction\n",
    "\n",
    "The dataset used for this tutorial is the [Iris dataset](https://www.tensorflow.org/datasets/catalog/iris) from [TensorFlow Datasets](https://www.tensorflow.org/datasets/catalog/overview). This dataset does not require any feature engineering. The version of the dataset you will use in this tutorial is stored in a public Cloud Storage bucket. The trained model predicts the type of Iris flower species from a class of three species: setosa, virginica, or versicolor."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "title:migration,new",
    "tags": []
   },
   "source": [
    "Each learning objective will correspond to a __#TODO__ in the [student lab notebook](../labs/sdk_customm_xgboost.ipynb) -- try to complete that notebook first before reviewing this solution notebook."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "install_aip:mbsdk"
   },
   "source": [
    "## Installation\n",
    "\n",
    "Install the latest version of Vertex SDK for Python."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "id": "install_aip:mbsdk"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: google-cloud-aiplatform in /opt/conda/lib/python3.7/site-packages (1.13.0)\n",
      "Requirement already satisfied: packaging>=14.3 in /opt/conda/lib/python3.7/site-packages (from google-cloud-aiplatform) (21.3)\n",
      "Requirement already satisfied: google-cloud-resource-manager<3.0.0dev,>=1.3.3 in /opt/conda/lib/python3.7/site-packages (from google-cloud-aiplatform) (1.4.1)\n",
      "Requirement already satisfied: google-cloud-bigquery<3.0.0dev,>=1.15.0 in /opt/conda/lib/python3.7/site-packages (from google-cloud-aiplatform) (2.34.3)\n",
      "Requirement already satisfied: proto-plus>=1.15.0 in /opt/conda/lib/python3.7/site-packages (from google-cloud-aiplatform) (1.20.3)\n",
      "Requirement already satisfied: google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5 in /opt/conda/lib/python3.7/site-packages (from google-cloud-aiplatform) (2.7.1)\n",
      "Requirement already satisfied: google-cloud-storage<3.0.0dev,>=1.32.0 in /opt/conda/lib/python3.7/site-packages (from google-cloud-aiplatform) (2.3.0)\n",
      "Requirement already satisfied: googleapis-common-protos<2.0dev,>=1.52.0 in /opt/conda/lib/python3.7/site-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (1.56.1)\n",
      "Requirement already satisfied: protobuf>=3.12.0 in /opt/conda/lib/python3.7/site-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (3.20.1)\n",
      "Requirement already satisfied: google-auth<3.0dev,>=1.25.0 in /opt/conda/lib/python3.7/site-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (1.35.0)\n",
      "Requirement already satisfied: requests<3.0.0dev,>=2.18.0 in /opt/conda/lib/python3.7/site-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (2.27.1)\n",
      "Requirement already satisfied: grpcio-status<2.0dev,>=1.33.2 in /opt/conda/lib/python3.7/site-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (1.46.1)\n",
      "Requirement already satisfied: grpcio<2.0dev,>=1.33.2 in /opt/conda/lib/python3.7/site-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (1.46.1)\n",
      "Requirement already satisfied: google-cloud-core<3.0.0dev,>=1.4.1 in /opt/conda/lib/python3.7/site-packages (from google-cloud-bigquery<3.0.0dev,>=1.15.0->google-cloud-aiplatform) (2.3.0)\n",
      "Requirement already satisfied: google-resumable-media<3.0dev,>=0.6.0 in /opt/conda/lib/python3.7/site-packages (from google-cloud-bigquery<3.0.0dev,>=1.15.0->google-cloud-aiplatform) (2.3.2)\n",
      "Requirement already satisfied: python-dateutil<3.0dev,>=2.7.2 in /opt/conda/lib/python3.7/site-packages (from google-cloud-bigquery<3.0.0dev,>=1.15.0->google-cloud-aiplatform) (2.8.2)\n",
      "Requirement already satisfied: grpc-google-iam-v1<0.13dev,>=0.12.3 in /opt/conda/lib/python3.7/site-packages (from google-cloud-resource-manager<3.0.0dev,>=1.3.3->google-cloud-aiplatform) (0.12.4)\n",
      "Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in /opt/conda/lib/python3.7/site-packages (from packaging>=14.3->google-cloud-aiplatform) (3.0.9)\n",
      "Requirement already satisfied: pyasn1-modules>=0.2.1 in /opt/conda/lib/python3.7/site-packages (from google-auth<3.0dev,>=1.25.0->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (0.2.7)\n",
      "Requirement already satisfied: rsa<5,>=3.1.4 in /opt/conda/lib/python3.7/site-packages (from google-auth<3.0dev,>=1.25.0->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (4.8)\n",
      "Requirement already satisfied: six>=1.9.0 in /opt/conda/lib/python3.7/site-packages (from google-auth<3.0dev,>=1.25.0->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (1.15.0)\n",
      "Requirement already satisfied: cachetools<5.0,>=2.0.0 in /opt/conda/lib/python3.7/site-packages (from google-auth<3.0dev,>=1.25.0->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (4.2.4)\n",
      "Requirement already satisfied: setuptools>=40.3.0 in /opt/conda/lib/python3.7/site-packages (from google-auth<3.0dev,>=1.25.0->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (59.8.0)\n",
      "Requirement already satisfied: google-crc32c<2.0dev,>=1.0 in /opt/conda/lib/python3.7/site-packages (from google-resumable-media<3.0dev,>=0.6.0->google-cloud-bigquery<3.0.0dev,>=1.15.0->google-cloud-aiplatform) (1.1.2)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /opt/conda/lib/python3.7/site-packages (from requests<3.0.0dev,>=2.18.0->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (3.3)\n",
      "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /opt/conda/lib/python3.7/site-packages (from requests<3.0.0dev,>=2.18.0->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (1.26.9)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.7/site-packages (from requests<3.0.0dev,>=2.18.0->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (2021.10.8)\n",
      "Requirement already satisfied: charset-normalizer~=2.0.0 in /opt/conda/lib/python3.7/site-packages (from requests<3.0.0dev,>=2.18.0->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (2.0.12)\n",
      "Requirement already satisfied: cffi>=1.0.0 in /opt/conda/lib/python3.7/site-packages (from google-crc32c<2.0dev,>=1.0->google-resumable-media<3.0dev,>=0.6.0->google-cloud-bigquery<3.0.0dev,>=1.15.0->google-cloud-aiplatform) (1.15.0)\n",
      "Requirement already satisfied: pyasn1<0.5.0,>=0.4.6 in /opt/conda/lib/python3.7/site-packages (from pyasn1-modules>=0.2.1->google-auth<3.0dev,>=1.25.0->google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-aiplatform) (0.4.8)\n",
      "Requirement already satisfied: pycparser in /opt/conda/lib/python3.7/site-packages (from cffi>=1.0.0->google-crc32c<2.0dev,>=1.0->google-resumable-media<3.0dev,>=0.6.0->google-cloud-bigquery<3.0.0dev,>=1.15.0->google-cloud-aiplatform) (2.21)\n"
     ]
    }
   ],
   "source": [
    "# import necessary libraries\n",
    "import os\n",
    "\n",
    "# Google Cloud Notebook\n",
    "if os.path.exists(\"/opt/deeplearning/metadata/env_version\"):\n",
    "    USER_FLAG = \"--user\"\n",
    "else:\n",
    "    USER_FLAG = \"\"\n",
    "\n",
    "! pip3 install --upgrade google-cloud-aiplatform $USER_FLAG"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "install_storage"
   },
   "source": [
    "Install the latest GA version of *google-cloud-storage* library as well."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "id": "install_storage"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: google-cloud-storage in /opt/conda/lib/python3.7/site-packages (2.3.0)\n",
      "Requirement already satisfied: google-auth<3.0dev,>=1.25.0 in /opt/conda/lib/python3.7/site-packages (from google-cloud-storage) (1.35.0)\n",
      "Requirement already satisfied: requests<3.0.0dev,>=2.18.0 in /opt/conda/lib/python3.7/site-packages (from google-cloud-storage) (2.27.1)\n",
      "Requirement already satisfied: google-cloud-core<3.0dev,>=2.3.0 in /opt/conda/lib/python3.7/site-packages (from google-cloud-storage) (2.3.0)\n",
      "Requirement already satisfied: google-resumable-media>=2.3.2 in /opt/conda/lib/python3.7/site-packages (from google-cloud-storage) (2.3.2)\n",
      "Requirement already satisfied: protobuf in /opt/conda/lib/python3.7/site-packages (from google-cloud-storage) (3.20.1)\n",
      "Requirement already satisfied: google-api-core!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5 in /opt/conda/lib/python3.7/site-packages (from google-cloud-storage) (2.7.1)\n",
      "Requirement already satisfied: googleapis-common-protos<2.0dev,>=1.52.0 in /opt/conda/lib/python3.7/site-packages (from google-api-core!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.0,<3.0.0dev,>=1.31.5->google-cloud-storage) (1.56.1)\n",
      "Requirement already satisfied: cachetools<5.0,>=2.0.0 in /opt/conda/lib/python3.7/site-packages (from google-auth<3.0dev,>=1.25.0->google-cloud-storage) (4.2.4)\n",
      "Requirement already satisfied: pyasn1-modules>=0.2.1 in /opt/conda/lib/python3.7/site-packages (from google-auth<3.0dev,>=1.25.0->google-cloud-storage) (0.2.7)\n",
      "Requirement already satisfied: setuptools>=40.3.0 in /opt/conda/lib/python3.7/site-packages (from google-auth<3.0dev,>=1.25.0->google-cloud-storage) (59.8.0)\n",
      "Requirement already satisfied: six>=1.9.0 in /opt/conda/lib/python3.7/site-packages (from google-auth<3.0dev,>=1.25.0->google-cloud-storage) (1.15.0)\n",
      "Requirement already satisfied: rsa<5,>=3.1.4 in /opt/conda/lib/python3.7/site-packages (from google-auth<3.0dev,>=1.25.0->google-cloud-storage) (4.8)\n",
      "Requirement already satisfied: google-crc32c<2.0dev,>=1.0 in /opt/conda/lib/python3.7/site-packages (from google-resumable-media>=2.3.2->google-cloud-storage) (1.1.2)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.7/site-packages (from requests<3.0.0dev,>=2.18.0->google-cloud-storage) (2021.10.8)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /opt/conda/lib/python3.7/site-packages (from requests<3.0.0dev,>=2.18.0->google-cloud-storage) (3.3)\n",
      "Requirement already satisfied: charset-normalizer~=2.0.0 in /opt/conda/lib/python3.7/site-packages (from requests<3.0.0dev,>=2.18.0->google-cloud-storage) (2.0.12)\n",
      "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /opt/conda/lib/python3.7/site-packages (from requests<3.0.0dev,>=2.18.0->google-cloud-storage) (1.26.9)\n",
      "Requirement already satisfied: cffi>=1.0.0 in /opt/conda/lib/python3.7/site-packages (from google-crc32c<2.0dev,>=1.0->google-resumable-media>=2.3.2->google-cloud-storage) (1.15.0)\n",
      "Requirement already satisfied: pyasn1<0.5.0,>=0.4.6 in /opt/conda/lib/python3.7/site-packages (from pyasn1-modules>=0.2.1->google-auth<3.0dev,>=1.25.0->google-cloud-storage) (0.4.8)\n",
      "Requirement already satisfied: pycparser in /opt/conda/lib/python3.7/site-packages (from cffi>=1.0.0->google-crc32c<2.0dev,>=1.0->google-resumable-media>=2.3.2->google-cloud-storage) (2.21)\n"
     ]
    }
   ],
   "source": [
    "! pip3 install -U google-cloud-storage $USER_FLAG"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "id": "install_tensorflow"
   },
   "outputs": [],
   "source": [
    "if os.getenv(\"IS_TESTING\"):\n",
    "    ! pip3 install --upgrade tensorflow $USER_FLAG"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "restart"
   },
   "source": [
    "### Restart the kernel\n",
    "\n",
    "Once you've installed the additional packages, you need to restart the notebook kernel so it can find the packages."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "id": "restart"
   },
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "if not os.getenv(\"IS_TESTING\"):\n",
    "    # Automatically restart kernel after installs\n",
    "    import IPython\n",
    "\n",
    "    app = IPython.Application.instance()\n",
    "    app.kernel.do_shutdown(True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "before_you_begin:nogpu"
   },
   "source": [
    "### Set up your Google Cloud project"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "id": "set_project_id"
   },
   "outputs": [],
   "source": [
    "PROJECT_ID = \"<your-project>\"  # replace with your project ID"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "id": "autoset_project_id"
   },
   "outputs": [],
   "source": [
    "if PROJECT_ID == \"\" or PROJECT_ID is None or PROJECT_ID == \"[your-project-id]\":\n",
    "    # Get your GCP project id from gcloud\n",
    "    shell_output = ! gcloud config list --format 'value(core.project)' 2>/dev/null\n",
    "    PROJECT_ID = shell_output[0]\n",
    "    print(\"Project ID:\", PROJECT_ID)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "id": "set_gcloud_project_id"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Updated property [core/project].\n"
     ]
    }
   ],
   "source": [
    "! gcloud config set project $PROJECT_ID"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "region"
   },
   "source": [
    "#### Region\n",
    "\n",
    "You can also change the `REGION` variable, which is used for operations\n",
    "throughout the rest of this notebook.  Below are regions supported for Vertex AI. We recommend that you choose the region closest to you.\n",
    "\n",
    "- Americas: `us-central1`\n",
    "- Europe: `europe-west4`\n",
    "- Asia Pacific: `asia-east1`\n",
    "\n",
    "You may not use a multi-regional bucket for training with Vertex AI. Not all regions provide support for all Vertex AI services.\n",
    "\n",
    "Learn more about [Vertex AI regions](https://cloud.google.com/vertex-ai/docs/general/locations)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "id": "region"
   },
   "outputs": [],
   "source": [
    "REGION = \"us-central1\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "timestamp"
   },
   "source": [
    "#### Timestamp\n",
    "\n",
    "If you are in a live tutorial session, you might be using a shared test account or project. To avoid name collisions between users on resources created, you create a timestamp for each instance session, and append the timestamp onto the name of resources you create in this tutorial."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "id": "timestamp"
   },
   "outputs": [],
   "source": [
    "from datetime import datetime\n",
    "\n",
    "TIMESTAMP = datetime.now().strftime(\"%Y%m%d%H%M%S\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "bucket:mbsdk"
   },
   "source": [
    "### Create a Cloud Storage bucket\n",
    "\n",
    "When you initialize the Vertex SDK for Python, you specify a Cloud Storage staging bucket. The staging bucket is where all the data associated with your dataset and model resources are retained across sessions.\n",
    "\n",
    "Set the name of your Cloud Storage bucket below. Bucket names must be globally unique across all Google Cloud projects, including those outside of your organization."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "id": "bucket"
   },
   "outputs": [],
   "source": [
    "BUCKET_NAME = \"gs://<your-bucket>\" # replace bucket name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "id": "autoset_bucket"
   },
   "outputs": [],
   "source": [
    "if BUCKET_NAME == \"\" or BUCKET_NAME is None or BUCKET_NAME == \"gs://[your-bucket-name]\":\n",
    "    BUCKET_NAME = \"gs://\" + PROJECT_ID + \"aip-\" + TIMESTAMP"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "create_bucket"
   },
   "source": [
    "**Only if your bucket doesn't already exist**: Run the following cell to create your Cloud Storage bucket."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "id": "create_bucket"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Creating gs://qwiklabs-gcp-02-c816472a2d85/...\n"
     ]
    }
   ],
   "source": [
    "! gcloud storage buckets create --location=$REGION $BUCKET_NAME"   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "validate_bucket"
   },
   "source": [
    "Finally, validate access to your Cloud Storage bucket by examining its contents:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "id": "validate_bucket"
   },
   "outputs": [],
   "source": [
    "! gcloud storage ls --all-versions --long $BUCKET_NAME"   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "setup_vars"
   },
   "source": [
    "### Set up variables\n",
    "\n",
    "Next, set up some variables used in this notebook.\n",
    "### Import libraries and define constants"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "id": "import_aip:mbsdk"
   },
   "outputs": [],
   "source": [
    "import google.cloud.aiplatform as aip"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "init_aip:mbsdk"
   },
   "source": [
    "## Initialize Vertex SDK for Python\n",
    "\n",
    "Initialize the Vertex SDK for Python for your project and corresponding bucket."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "id": "init_aip:mbsdk"
   },
   "outputs": [],
   "source": [
    "aip.init(project=PROJECT_ID, staging_bucket=BUCKET_NAME)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "container:training,prediction,xgboost"
   },
   "source": [
    "#### Set pre-built containers\n",
    "\n",
    "Set the pre-built Docker container image for training and prediction.\n",
    "\n",
    "\n",
    "For the latest list, see [Pre-built containers for training](https://cloud.google.com/ai-platform-unified/docs/training/pre-built-containers).\n",
    "\n",
    "\n",
    "For the latest list, see [Pre-built containers for prediction](https://cloud.google.com/ai-platform-unified/docs/predictions/pre-built-containers)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "id": "container:training,prediction,xgboost"
   },
   "outputs": [],
   "source": [
    "TRAIN_VERSION = \"xgboost-cpu.1-1\"\n",
    "DEPLOY_VERSION = \"xgboost-cpu.1-1\"\n",
    "\n",
    "TRAIN_IMAGE = \"gcr.io/cloud-aiplatform/training/{}:latest\".format(TRAIN_VERSION)\n",
    "DEPLOY_IMAGE = \"gcr.io/cloud-aiplatform/prediction/{}:latest\".format(DEPLOY_VERSION)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "machine:training,prediction"
   },
   "source": [
    "#### Set machine type\n",
    "\n",
    "Next, set the machine type to use for training and prediction.\n",
    "\n",
    "- Set the variables `TRAIN_COMPUTE` and `DEPLOY_COMPUTE` to configure  the compute resources for the VMs you will use for for training and prediction.\n",
    " - `machine type`\n",
    "     - `n1-standard`: 3.75GB of memory per vCPU.\n",
    "     - `n1-highmem`: 6.5GB of memory per vCPU\n",
    "     - `n1-highcpu`: 0.9 GB of memory per vCPU\n",
    " - `vCPUs`: number of \\[2, 4, 8, 16, 32, 64, 96 \\]\n",
    "\n",
    "*Note: The following is not supported for training:*\n",
    "\n",
    " - `standard`: 2 vCPUs\n",
    " - `highcpu`: 2, 4 and 8 vCPUs\n",
    "\n",
    "*Note: You may also use n2 and e2 machine types for training and deployment, but they do not support GPUs*."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "id": "machine:training,prediction"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train machine type n1-standard-4\n",
      "Deploy machine type n1-standard-4\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "if os.getenv(\"IS_TESTING_TRAIN_MACHINE\"):\n",
    "    MACHINE_TYPE = os.getenv(\"IS_TESTING_TRAIN_MACHINE\")\n",
    "else:\n",
    "    MACHINE_TYPE = \"n1-standard\"\n",
    "\n",
    "VCPU = \"4\"\n",
    "TRAIN_COMPUTE = MACHINE_TYPE + \"-\" + VCPU\n",
    "print(\"Train machine type\", TRAIN_COMPUTE)\n",
    "\n",
    "if os.getenv(\"IS_TESTING_DEPLOY_MACHINE\"):\n",
    "    MACHINE_TYPE = os.getenv(\"IS_TESTING_DEPLOY_MACHINE\")\n",
    "else:\n",
    "    MACHINE_TYPE = \"n1-standard\"\n",
    "\n",
    "VCPU = \"4\"\n",
    "DEPLOY_COMPUTE = MACHINE_TYPE + \"-\" + VCPU\n",
    "print(\"Deploy machine type\", DEPLOY_COMPUTE)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "examine_training_package"
   },
   "source": [
    "### Examine the training package\n",
    "\n",
    "#### Package layout\n",
    "\n",
    "Before you start the training, you will look at how a Python package is assembled for a custom training job. When unarchived, the package contains the following directory/file layout.\n",
    "\n",
    "- PKG-INFO\n",
    "- README.md\n",
    "- setup.cfg\n",
    "- setup.py\n",
    "- trainer\n",
    "  - \\_\\_init\\_\\_.py\n",
    "  - task.py\n",
    "\n",
    "The files `setup.cfg` and `setup.py` are the instructions for installing the package into the operating environment of the Docker image.\n",
    "\n",
    "The file `trainer/task.py` is the Python script for executing the custom training job. *Note*, when we referred to it in the worker pool specification, we replace the directory slash with a dot (`trainer.task`) and dropped the file suffix (`.py`).\n",
    "\n",
    "#### Package Assembly\n",
    "\n",
    "In the following cells, you will assemble the training package."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "id": "examine_training_package"
   },
   "outputs": [],
   "source": [
    "# Make folder for Python training script\n",
    "! rm -rf custom\n",
    "! mkdir custom\n",
    "\n",
    "# Add package information\n",
    "! touch custom/README.md\n",
    "\n",
    "setup_cfg = \"[egg_info]\\n\\ntag_build =\\n\\ntag_date = 0\"\n",
    "! echo \"$setup_cfg\" > custom/setup.cfg\n",
    "\n",
    "setup_py = \"import setuptools\\n\\nsetuptools.setup(\\n\\n    install_requires=[\\n\\n        'tensorflow_datasets==1.3.0',\\n\\n    ],\\n\\n    packages=setuptools.find_packages())\"\n",
    "! echo \"$setup_py\" > custom/setup.py\n",
    "\n",
    "pkg_info = \"Metadata-Version: 1.0\\n\\nName: Iris tabular classification\\n\\nVersion: 0.0.0\\n\\nSummary: Demostration training script\\n\\nHome-page: www.google.com\\n\\nAuthor: Google\\n\\nAuthor-email: aferlitsch@google.com\\n\\nLicense: Public\\n\\nDescription: Demo\\n\\nPlatform: Vertex\"\n",
    "! echo \"$pkg_info\" > custom/PKG-INFO\n",
    "\n",
    "# Make the training subfolder\n",
    "! mkdir custom/trainer\n",
    "! touch custom/trainer/__init__.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "id": "taskpy_contents:xgboost,iris"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing custom/trainer/task.py\n"
     ]
    }
   ],
   "source": [
    "%%writefile custom/trainer/task.py\n",
    "# Single Instance Training for Iris\n",
    "\n",
    "import datetime\n",
    "import os\n",
    "import subprocess\n",
    "import sys\n",
    "import pandas as pd\n",
    "import xgboost as xgb\n",
    "\n",
    "import argparse\n",
    "\n",
    "parser = argparse.ArgumentParser()\n",
    "parser.add_argument('--model-dir', dest='model_dir',\n",
    "                    default=os.getenv('AIP_MODEL_DIR'), type=str, help='Model dir.')\n",
    "args = parser.parse_args()\n",
    "\n",
    "# Download data\n",
    "iris_data_filename = 'iris_data.csv'\n",
    "iris_target_filename = 'iris_target.csv'\n",
    "data_dir = 'gs://cloud-samples-data/ai-platform/iris'\n",
    "\n",
    "# gsutil outputs everything to stderr so we need to divert it to stdout.\n",
    "subprocess.check_call(['gcloud', 'storage', 'cp', os.path.join(data_dir,\n"    "                                                    iris_data_filename),\n",
    "                       iris_data_filename], stderr=sys.stdout)\n",
    "subprocess.check_call(['gcloud', 'storage', 'cp', os.path.join(data_dir,\n",    "                                                    iris_target_filename),\n",
    "                       iris_target_filename], stderr=sys.stdout)\n",
    "\n",
    "\n",
    "# Load data into pandas, then use `.values` to get NumPy arrays\n",
    "iris_data = pd.read_csv(iris_data_filename).values\n",
    "iris_target = pd.read_csv(iris_target_filename).values\n",
    "\n",
    "# Convert one-column 2D array into 1D array for use with XGBoost\n",
    "iris_target = iris_target.reshape((iris_target.size,))\n",
    "\n",
    "\n",
    "# Load data into DMatrix object\n",
    "dtrain = xgb.DMatrix(iris_data, label=iris_target)\n",
    "\n",
    "\n",
    "# Train XGBoost model\n",
    "bst = xgb.train({}, dtrain, 20)\n",
    "\n",
    "# Export the classifier to a file\n",
    "model_filename = 'model.bst'\n",
    "bst.save_model(model_filename)\n",
    "\n",
    "# Upload the saved model file to Cloud Storage\n",
    "gcs_model_path = os.path.join(args.model_dir, model_filename)\n",
    "subprocess.check_call(['gcloud', 'storage', 'cp', model_filename, gcs_model_path],\n",
    "    stderr=sys.stdout)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "tarball_training_script"
   },
   "source": [
    "#### Store training script on your Cloud Storage bucket\n",
    "\n",
    "Next, you package the training folder into a compressed tar ball, and then store it in your Cloud Storage bucket."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "id": "tarball_training_script"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom/\n",
      "custom/trainer/\n",
      "custom/trainer/__init__.py\n",
      "custom/trainer/task.py\n",
      "custom/setup.py\n",
      "custom/README.md\n",
      "custom/PKG-INFO\n",
      "custom/setup.cfg\n",
      "Copying file://custom.tar.gz [Content-Type=application/x-tar]...\n",
      "/ [1 files][  1.2 KiB/  1.2 KiB]                                                \n",
      "Operation completed over 1 objects/1.2 KiB.                                      \n"
     ]
    }
   ],
   "source": [
    "! rm -f custom.tar custom.tar.gz\n",
    "! tar cvf custom.tar custom\n",
    "! gzip custom.tar\n",
    "! gcloud storage cp custom.tar.gz $BUCKET_NAME/trainer_iris.tar.gz"   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "train_a_model:migration"
   },
   "source": [
    "## Train a model ([training.create-python-pre-built-container](https://cloud.google.com/vertex-ai/docs/training/create-python-pre-built-container))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "create_custom_training_job:mbsdk,no_model"
   },
   "source": [
    "### Create and run custom training job\n",
    "\n",
    "\n",
    "To train a custom model, you perform two steps: 1) create a custom training job, and 2) run the job.\n",
    "\n",
    "#### Create custom training job\n",
    "\n",
    "A custom training job is created with the `CustomTrainingJob` class, with the following parameters:\n",
    "\n",
    "- `display_name`: The human readable name for the custom training job.\n",
    "- `container_uri`: The training container image.\n",
    "- `requirements`: Package requirements for the training container image (e.g., pandas).\n",
    "- `script_path`: The relative path to the training script."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "id": "create_custom_training_job:mbsdk,no_model"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<google.cloud.aiplatform.training_jobs.CustomTrainingJob object at 0x7fcf426eb350>\n"
     ]
    }
   ],
   "source": [
    "# TODO\n",
    "# constructs a Custom Training Job using a Python script\n",
    "job = aip.CustomTrainingJob(\n",
    "    display_name=\"iris_\" + TIMESTAMP,\n",
    "    script_path=\"custom/trainer/task.py\",\n",
    "    container_uri=TRAIN_IMAGE,\n",
    "    requirements=[\"gcsfs==0.7.1\", \"tensorflow-datasets==4.4\"],\n",
    ")\n",
    "\n",
    "print(job)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "run_custom_job:mbsdk,no_model,cpu"
   },
   "source": [
    "#### Run the custom training job\n",
    "\n",
    "Next, you run the custom job to start the training job by invoking the method `run`, with the following parameters:\n",
    "\n",
    "- `replica_count`: The number of compute instances for training (replica_count = 1 is single node training).\n",
    "- `machine_type`: The machine type for the compute instances.\n",
    "- `base_output_dir`: The Cloud Storage location to write the model artifacts to.\n",
    "- `sync`: Whether to block until completion of the job."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "id": "run_custom_job:mbsdk,no_model,cpu"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Training script copied to:\n",
      "gs://qwiklabs-gcp-02-c816472a2d85/aiplatform-2022-05-25-12:52:36.960-aiplatform_custom_trainer_script-0.1.tar.gz.\n",
      "Training Output directory:\n",
      "gs://qwiklabs-gcp-02-c816472a2d85/20220525124911 \n",
      "View Training:\n",
      "https://console.cloud.google.com/ai/platform/locations/us-central1/training/6485750261657632768?project=781054085410\n",
      "CustomTrainingJob projects/781054085410/locations/us-central1/trainingPipelines/6485750261657632768 current state:\n",
      "PipelineState.PIPELINE_STATE_PENDING\n",
      "CustomTrainingJob projects/781054085410/locations/us-central1/trainingPipelines/6485750261657632768 current state:\n",
      "PipelineState.PIPELINE_STATE_PENDING\n",
      "View backing custom job:\n",
      "https://console.cloud.google.com/ai/platform/locations/us-central1/training/7486651089584914432?project=781054085410\n",
      "CustomTrainingJob projects/781054085410/locations/us-central1/trainingPipelines/6485750261657632768 current state:\n",
      "PipelineState.PIPELINE_STATE_RUNNING\n",
      "CustomTrainingJob projects/781054085410/locations/us-central1/trainingPipelines/6485750261657632768 current state:\n",
      "PipelineState.PIPELINE_STATE_RUNNING\n",
      "CustomTrainingJob projects/781054085410/locations/us-central1/trainingPipelines/6485750261657632768 current state:\n",
      "PipelineState.PIPELINE_STATE_RUNNING\n",
      "CustomTrainingJob run completed. Resource name: projects/781054085410/locations/us-central1/trainingPipelines/6485750261657632768\n",
      "Training did not produce a Managed Model returning None. Training Pipeline projects/781054085410/locations/us-central1/trainingPipelines/6485750261657632768 is not configured to upload a Model. Create the Training Pipeline with model_serving_container_image_uri and model_display_name passed in. Ensure that your training script saves to model to os.environ['AIP_MODEL_DIR'].\n"
     ]
    }
   ],
   "source": [
    "MODEL_DIR = \"{}/{}\".format(BUCKET_NAME, TIMESTAMP)\n",
    "\n",
    "\n",
    "job.run(\n",
    "    replica_count=1, machine_type=TRAIN_COMPUTE, base_output_dir=MODEL_DIR, sync=True\n",
    ")\n",
    "\n",
    "MODEL_DIR = MODEL_DIR + \"/model\"\n",
    "model_path_to_deploy = MODEL_DIR"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "run_custom_job:mbsdk,no_model,cpu"
   },
   "source": [
    " **The custom training job will take some time to complete**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "upload_model:mbsdk"
   },
   "source": [
    "## Upload the model ([general.import-model](https://cloud.google.com/vertex-ai/docs/general/import-model))\n",
    "\n",
    "Next, upload your model to a `Model` resource using `Model.upload()` method, with the following parameters:\n",
    "\n",
    "- `display_name`: The human readable name for the `Model` resource.\n",
    "- `artifact_uri`: The Cloud Storage location of the trained model artifacts.\n",
    "- `serving_container_image_uri`: The serving container image.\n",
    "- `sync`: Whether to execute the upload asynchronously or synchronously.\n",
    "\n",
    "If the `upload()` method is run asynchronously, you can subsequently block until completion with the `wait()` method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "id": "upload_model:mbsdk"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Creating Model\n",
      "Create Model backing LRO: projects/781054085410/locations/us-central1/models/6501425449179021312/operations/1923258661199675392\n",
      "Model created. Resource name: projects/781054085410/locations/us-central1/models/6501425449179021312\n",
      "To use this Model in another session:\n",
      "model = aiplatform.Model('projects/781054085410/locations/us-central1/models/6501425449179021312')\n"
     ]
    }
   ],
   "source": [
    "# TODO\n",
    "model = aip.Model.upload(\n",
    "    display_name=\"iris_\" + TIMESTAMP,\n",
    "    artifact_uri=MODEL_DIR,\n",
    "    serving_container_image_uri=DEPLOY_IMAGE,\n",
    "    sync=False,\n",
    ")\n",
    "\n",
    "model.wait()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "make_batch_predictions:migration"
   },
   "source": [
    "## Make batch predictions ([predictions.batch-prediction](https://cloud.google.com/vertex-ai/docs/predictions/batch-predictions))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "make_test_items:xgboost,tabular,iris"
   },
   "source": [
    "### Make test items\n",
    "\n",
    "You will use synthetic data as a test data items. Don't be concerned that we are using synthetic data -- we just want to demonstrate how to make a prediction."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "id": "make_test_items:xgboost,tabular,iris"
   },
   "outputs": [],
   "source": [
    "INSTANCES = [[1.4, 1.3, 5.1, 2.8], [1.5, 1.2, 4.7, 2.4]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "make_batch_file:custom,tabular,list"
   },
   "source": [
    "### Make the batch input file\n",
    "\n",
    "Now make a batch input file, which you will store in your local Cloud Storage bucket.  Each instance in the prediction request is a list of the form:\n",
    "\n",
    "                        [ [ content_1], [content_2] ]\n",
    "\n",
    "- `content`: The feature values of the test item as a list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "id": "make_batch_file:custom,tabular,list"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1.4, 1.3, 5.1, 2.8]\n",
      "[1.5, 1.2, 4.7, 2.4]\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "\n",
    "gcs_input_uri = BUCKET_NAME + \"/\" + \"test.jsonl\"\n",
    "with tf.io.gfile.GFile(gcs_input_uri, \"w\") as f:\n",
    "    for i in INSTANCES:\n",
    "        f.write(str(i) + \"\\n\")\n",
    "\n",
    "! gcloud storage cat $gcs_input_uri"   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "batch_request:mbsdk,jsonl,custom,cpu"
   },
   "source": [
    "### Make the batch prediction request\n",
    "\n",
    "Now that your Model resource is trained, you can make a batch prediction by invoking the `batch_predict()` method, with the following parameters:\n",
    "\n",
    "- `job_display_name`: The human readable name for the batch prediction job.\n",
    "- `gcs_source`: A list of one or more batch request input files.\n",
    "- `gcs_destination_prefix`: The Cloud Storage location for storing the batch prediction resuls.\n",
    "- `instances_format`: The format for the input instances, either 'csv' or 'jsonl'. Defaults to 'jsonl'.\n",
    "- `predictions_format`: The format for the output predictions, either 'csv' or 'jsonl'. Defaults to 'jsonl'.\n",
    "- `machine_type`: The type of machine to use for training.\n",
    "- `sync`: If set to True, the call will block while waiting for the asynchronous batch job to complete."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "id": "batch_request:mbsdk,jsonl,custom,cpu"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Creating BatchPredictionJob\n",
      "<google.cloud.aiplatform.jobs.BatchPredictionJob object at 0x7fcf033fb350> is waiting for upstream dependencies to complete.\n",
      "BatchPredictionJob created. Resource name: projects/781054085410/locations/us-central1/batchPredictionJobs/1684343511857496064\n",
      "To use this BatchPredictionJob in another session:\n",
      "bpj = aiplatform.BatchPredictionJob('projects/781054085410/locations/us-central1/batchPredictionJobs/1684343511857496064')\n",
      "View Batch Prediction Job:\n",
      "https://console.cloud.google.com/ai/platform/locations/us-central1/batch-predictions/1684343511857496064?project=781054085410\n",
      "BatchPredictionJob projects/781054085410/locations/us-central1/batchPredictionJobs/1684343511857496064 current state:\n",
      "JobState.JOB_STATE_PENDING\n",
      "BatchPredictionJob projects/781054085410/locations/us-central1/batchPredictionJobs/1684343511857496064 current state:\n",
      "JobState.JOB_STATE_RUNNING\n"
     ]
    }
   ],
   "source": [
    "MIN_NODES = 1\n",
    "MAX_NODES = 1\n",
    "\n",
    "# TODO\n",
    "batch_predict_job = model.batch_predict(\n",
    "    job_display_name=\"iris_\" + TIMESTAMP,\n",
    "    gcs_source=gcs_input_uri,\n",
    "    gcs_destination_prefix=BUCKET_NAME,\n",
    "    instances_format=\"jsonl\",\n",
    "    predictions_format=\"jsonl\",\n",
    "    model_parameters=None,\n",
    "    machine_type=DEPLOY_COMPUTE,\n",
    "    starting_replica_count=MIN_NODES,\n",
    "    max_replica_count=MAX_NODES,\n",
    "    sync=False,\n",
    ")\n",
    "\n",
    "print(batch_predict_job)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "run_custom_job:mbsdk,no_model,cpu"
   },
   "source": [
    " **Batch prediction request will take 25-30 mins to complete**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "get_batch_prediction:mbsdk,custom,lcn"
   },
   "source": [
    "### Get the predictions\n",
    "\n",
    "Next, get the results from the completed batch prediction job.\n",
    "\n",
    "The results are written to the Cloud Storage output bucket you specified in the batch prediction request. You call the method iter_outputs() to get a list of each Cloud Storage file generated with the results. Each file contains one or more prediction requests in a JSON format:\n",
    "\n",
    "- `instance`: The prediction request.\n",
    "- `prediction`: The prediction response."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "id": "get_batch_prediction:mbsdk,custom,lcn"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'instance': [1.5, 1.2, 4.7, 2.4], 'prediction': 1.9618644714355469}\n",
      "{'instance': [1.4, 1.3, 5.1, 2.8], 'prediction': 2.0451931953430176}\n"
     ]
    }
   ],
   "source": [
    "import json\n",
    "\n",
    "bp_iter_outputs = batch_predict_job.iter_outputs()\n",
    "\n",
    "prediction_results = list()\n",
    "for blob in bp_iter_outputs:\n",
    "    if blob.name.split(\"/\")[-1].startswith(\"prediction\"):\n",
    "        prediction_results.append(blob.name)\n",
    "\n",
    "tags = list()\n",
    "for prediction_result in prediction_results:\n",
    "    gfile_name = f\"gs://{bp_iter_outputs.bucket.name}/{prediction_result}\"\n",
    "    with tf.io.gfile.GFile(name=gfile_name, mode=\"r\") as gfile:\n",
    "        for line in gfile.readlines():\n",
    "            line = json.loads(line)\n",
    "            print(line)\n",
    "            break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "make_online_predictions:migration"
   },
   "source": [
    "## Make online predictions ([predictions.deploy-model-api](https://cloud.google.com/vertex-ai/docs/predictions/deploy-model-api))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "deploy_model:mbsdk,cpu"
   },
   "source": [
    "## Deploy the model\n",
    "\n",
    "Next, deploy your model for online prediction. To deploy the model, you invoke the `deploy` method, with the following parameters:\n",
    "\n",
    "- `deployed_model_display_name`: A human readable name for the deployed model.\n",
    "- `traffic_split`: Percent of traffic at the endpoint that goes to this model, which is specified as a dictionary of one or more key/value pairs.\n",
    "If only one model, then specify as { \"0\": 100 }, where \"0\" refers to this model being uploaded and 100 means 100% of the traffic.\n",
    "If there are existing models on the endpoint, for which the traffic will be split, then use model_id to specify as { \"0\": percent, model_id: percent, ... }, where model_id is the model id of an existing model to the deployed endpoint. The percents must add up to 100.\n",
    "- `machine_type`: The type of machine to use for training.\n",
    "- `min_replica_count`: The number of compute instances to initially provision.\n",
    "- `max_replica_count`: The maximum number of compute instances to scale to. In this tutorial, only one instance is provisioned."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "id": "deploy_model:mbsdk,cpu"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Creating Endpoint\n",
      "Create Endpoint backing LRO: projects/781054085410/locations/us-central1/endpoints/257575991969316864/operations/7331659601206575104\n",
      "Endpoint created. Resource name: projects/781054085410/locations/us-central1/endpoints/257575991969316864\n",
      "To use this Endpoint in another session:\n",
      "endpoint = aiplatform.Endpoint('projects/781054085410/locations/us-central1/endpoints/257575991969316864')\n",
      "Deploying model to Endpoint : projects/781054085410/locations/us-central1/endpoints/257575991969316864\n",
      "Deploy Endpoint model backing LRO: projects/781054085410/locations/us-central1/endpoints/257575991969316864/operations/7588786992431759360\n",
      "Endpoint model deployed. Resource name: projects/781054085410/locations/us-central1/endpoints/257575991969316864\n"
     ]
    }
   ],
   "source": [
    "DEPLOYED_NAME = \"iris-\" + TIMESTAMP\n",
    "\n",
    "TRAFFIC_SPLIT = {\"0\": 100}\n",
    "\n",
    "MIN_NODES = 1\n",
    "MAX_NODES = 1\n",
    "\n",
    "# TODO\n",
    "endpoint = model.deploy(\n",
    "    deployed_model_display_name=DEPLOYED_NAME,\n",
    "    traffic_split=TRAFFIC_SPLIT,\n",
    "    machine_type=DEPLOY_COMPUTE,\n",
    "    min_replica_count=MIN_NODES,\n",
    "    max_replica_count=MAX_NODES,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "run_custom_job:mbsdk,no_model,cpu"
   },
   "source": [
    " **Model deployment will take some time to complete**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "make_test_item:xgboost,tabular,iris"
   },
   "source": [
    "### Make test item ([predictions.online-prediction-automl](https://cloud.google.com/vertex-ai/docs/predictions/online-predictions-automl))\n",
    "\n",
    "You will use synthetic data as a test data item. Don't be concerned that we are using synthetic data -- we just want to demonstrate how to make a prediction."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "id": "make_test_item:xgboost,tabular,iris"
   },
   "outputs": [],
   "source": [
    "INSTANCE = [1.4, 1.3, 5.1, 2.8]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "predict_request:mbsdk,custom,lcn"
   },
   "source": [
    "### Make the prediction\n",
    "\n",
    "Now that your `Model` resource is deployed to an `Endpoint` resource, you can do online predictions by sending prediction requests to the `Endpoint` resource.\n",
    "\n",
    "#### Request\n",
    "\n",
    "The format of each instance is:\n",
    "\n",
    "    [feature_list]\n",
    "\n",
    "Since the predict() method can take multiple items (instances), send your single test item as a list of one test item.\n",
    "\n",
    "#### Response\n",
    "\n",
    "The response from the predict() call is a Python dictionary with the following entries:\n",
    "\n",
    "- `ids`: The internal assigned unique identifiers for each prediction request.\n",
    "- `predictions`: The predicted confidence, between 0 and 1, per class label.\n",
    "- `deployed_model_id`: The Vertex AI identifier for the deployed `Model` resource which did the predictions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "id": "predict_request:mbsdk,custom,lcn"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Prediction(predictions=[2.045193195343018], deployed_model_id='1444239309409353728', explanations=None)\n"
     ]
    }
   ],
   "source": [
    "instances_list = [INSTANCE]\n",
    "\n",
    "prediction = endpoint.predict(instances_list)\n",
    "print(prediction)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "undeploy_model:mbsdk"
   },
   "source": [
    "## Undeploy the model\n",
    "\n",
    "When you are done doing predictions, you undeploy the model from the `Endpoint` resouce. This deprovisions all compute resources and ends billing for the deployed model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "id": "undeploy_model:mbsdk"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Undeploying Endpoint model: projects/781054085410/locations/us-central1/endpoints/257575991969316864\n",
      "Undeploy Endpoint model backing LRO: projects/781054085410/locations/us-central1/endpoints/257575991969316864/operations/1112610728272986112\n",
      "Endpoint model undeployed. Resource name: projects/781054085410/locations/us-central1/endpoints/257575991969316864\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<google.cloud.aiplatform.models.Endpoint object at 0x7fcf030e12d0> \n",
       "resource name: projects/781054085410/locations/us-central1/endpoints/257575991969316864"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "endpoint.undeploy_all()"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "name": "UJ9 Vertex SDK Custom XGBoost with pre-built training container.ipynb",
   "toc_visible": true
  },
  "environment": {
   "kernel": "python3",
   "name": "tf2-gpu.2-6.m92",
   "type": "gcloud",
   "uri": "gcr.io/deeplearning-platform-release/tf2-gpu.2-6:m92"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
